(**************************************************************************)
(*       ___                                                              *)
(*      ||M||                                                             *)
(*      ||A||       A project by Andrea Asperti                           *)
(*      ||T||                                                             *)
(*      ||I||       Developers:                                           *)
(*      ||T||         The HELM team.                                      *)
(*      ||A||         http://helm.cs.unibo.it                             *)
(*      \   /                                                             *)
(*       \ /        This file is distributed under the terms of the       *)
(*        v         GNU General Public License Version 2                  *)
(*                                                                        *)
(**************************************************************************)
(**** 
After some experience in the use of Matita I could realize how
useful Andrea's tutorial:
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.149.7928
can be, since it is compact, and allows to focus on the esssential
aspects for a fruitful approach to Matita.
So, I decided to start converting it for the current (23rd 
of February 2013) version of Matita. The reason I like to have it
available via web browser is that, quite often, I access
Matita by my tablet.

For the moment I am very interested to the more 'advanced' parts,
i.e. those ones that start after double induction.
Initially, I will introduce the least amount of code which is
essential to have the advanced part working. Gradually, I plan to
include the whole text as comments to the code.

DISCLAIMER: 
Until not explicitly otherwise written, every part of the content
is due to Andrea.*)

include "basics/relations.ma".

(*****************************************************************)
(**************** Chapter 1. Getting started *********************)
(*****************************************************************)
(* Natural numbers are the smallest set generated by a constant O 
and a successor function S. Sets of this kind, freely generated by
a finite number of constructors, are known as inductive types.
The definition of natural numbers in Matita reads as follows: *)

inductive nat : Type[0] ≝
  | O : nat
  | S : nat → nat.
interpretation "Natural numbers" 'N = nat.
alias num (instance 0) = "natural number".

(* By this syntax, we declare we are defining an inductive type of 
name nat (which is a Type[0]), built up from the two constructors O 
of type nat and S of type nat → nat.
Let us now define a simple function over natural numbers. 
The sum of two natural numbers n and m may be defined as follows: 
if n is O then the sum is m, otherwise, if n is the successor of 
some natural number p, then the sum of n and m is equal to the 
successor of the sum of p and m. In this way, we have reduced the 
computation of the sum of two natural numbers to a similar problem, 
but on smaller input values. This is an example of a recursive 
definition, that is a definition of a function in terms of the 
function itself. In Matita, the previous definition of the sum 
over natural numbers would be written in the following way: *)

let rec plus n m ≝ 
 match n with [ O ⇒ m | S p ⇒ S (plus p m) ].
interpretation "natural plus" 'plus x y = (plus x y).

(* Equalities ***************************************************************)

theorem plus_O_n: ∀n:nat. n = O + n.
#n normalize @refl qed.

theorem plus_n_O: ∀n:nat. n = n + O.
#n (elim n) normalize 
[ @refl | #n #H <H @eq_f @refl ] qed.

theorem plus_n_Sm : ∀n,m:nat. S (n+m) = n + S m.
#n (elim n) normalize 
[#m @eq_f @refl 
|#m #H #p @eq_f <(H p) @eq_f @eq_f2 
 [@refl|@refl]] qed.
 
(* The monotonicity of plus is not in the original
Apserti's tutorial but, as far as I could understand
the way the current version of Matita works, requires
it to prove the equivalence of the two equivalence
relations le2 and le we shall see later. *)
theorem plus_monotone:∀n,m:nat. n=m → (S n) = (S m).
#n elim n  
[#m #Om <Om @eq_f @refl 
|#m #H #p #Smp >Smp @eq_f @refl] qed.

theorem plus_sym: ∀ n,m:nat. n+m = m+n.
#n #m elim n normalize
[ @plus_n_O
| #p #H >H @(plus_n_Sm m p)] qed.

(* Exercise: 
lemma not_eq_plus_S_m_O: ∀ n,m:nat. Not ((S n)+m = O).
#n #m @nmk >(plus_sym (S n) m) <(plus_n_Sm m n) #abs destruct qed .*)

(**************** Section 1.2 Double induction ***************)
theorem nat_elim2 :
 ∀R:nat → nat → Prop.
  (∀n:nat. R O n) 
  → (∀n:nat. R (S n) O)
  → (∀n,m:nat. R n m → R (S n) (S m))
  → ∀n,m:nat. R n m.
#R #ROn #RSO #RSS #n (elim n) 
[ @ROn
| #Pred_n #RPred_nm
  #m cases m
    [@(RSO Pred_n)
    |#m' @(RSS Pred_n m') @(RPred_nm m')]
] qed.

(**************** Section 1.3 Negation and Discrimination ***)
(* Two major axioms of Peano axiomatization of naturals are:
1) the inequality between O and S x, for any x, and
2) the injectivity of S. 
More generally, given any inductive type, we expect to be 
able to prove that all constructors are injective and 
distinguishable each from the other.

The statement ∀x. Not (O = (Sx)) is our first example 
involving negation.

In the logical framework of Matita, negation is not 
considered as a primitive connective, but is instead defined 
in terms of the absurdity proposition False. Explicitly, we 
may conclude Not P, if and only if assuming P leads 
to an asburdity, that is P → False.

What about False? The only logical principle related to 
False is the ancient property expressed by the latin motto 
'ex falso quodlibet', that is, everything may be deduced 
under a false assumption. 

Formally, this is expressed by the following property that, 
for the moment, we may assume to be a primitive constant 
of the system:

False_ind : ∀P:Prop. False → P

[Ndr: In fact, False_ind *is* a primitive in Matita as it 
is used in many points when building libraries! ]

Concerning injectivity (or separability) of constructors, 
Matita provides the tactic destruct. The tactic expects in 
input a term of type e1 = e2. It recursively compares e1 
and e2, skipping common constructors (injectivity) and halts
on subexpressions differing on their leftmost outermost 
symbols. If any of these correponding symbols are two 
different constructors the tactics automatically closes the 
goal [Ndr: that depends on them] having obtained a 
contradiction. Otherwise, destruct adds to the context all 
new equalities between the different subformulae in 
corresponding positions. Luckily, the tactic is much simpler
to use than to explain. Let us see a couple of examples. *)

theorem not_eq_O_S: ∀ n:nat. Not (O = S n).
#n (* apply the definition of Not *) @nmk #Habs destruct qed.

(* Exercise:
lemma not_eq_S_O: ∀ n:nat. Not (S n = O).
#n (* apply the definition of Not *) @nmk #Habs destruct qed. *)

theorem S_inj: ∀ n,m:nat. S n = S m → n = m.
#n #m #Hinj destruct @refl qed .

(*****************************************************************)
(**************** Chapter 2. Defining properties *****************)
(*****************************************************************)
(* So far, the only property we have been dealing with has 
been equality that we have essentially assumed as a 
primitive notion of Matita, governed via rewriting and 
reflexivity. As an exercise one can prove simmetry and 
transitivity of the equality, as follows: *)

lemma eq_sym: ∀A:Type[0]. ∀x,y:A. x=y → y=x.
#A #x #y #eqxy <eqxy @refl qed .

lemma eq_tran: ∀A:Type[0]. ∀x,y,z:A. x=y → y=z → x=z.
#A #x #y #z #eqxy #eqyz >eqxy @eqyz qed .

(* The next step is to define a binary predicate 
le n m 
asserting that n is less or equal to m. As we shall see, 
we have some alternatives.

We start with a natural mathematical definition: 
n is less or equal to m 
  if and only if it exists p such n + p = m. 

We have essentially two different, almost equivalent, ways
to encode such a predicate in Matita: 
1) as a definition, or 
2) as an inductive type.

As a definition it is: *)

definition le1: nat → nat → Prop ≝
                       λn,m.∃p:nat.n+p = m.

(* However, an experienced Matita user would probably prefer
to transform the previous definition of le into the smallest
property induced by *an integer p and a proof of n+p=m * 
as follows:*)

inductive le2 (n,m:nat) : Prop ≝
le_witness : ∀p:nat.n+p = m → le2 n m.

(* The constructor le_witness is a user-defined name that
can bw chosen arbitrarily and which idetifies a proof of:
    
    ∀n,m,p:nat.n + p = m → le2 n m

Namely, the two parameters n and m are also parameters 
for the constructor whose fully blown type is exactly:

     le_witness: ∀n,m,p:nat.n + p = m → le2 n m

We formally prove the equivalence between the two
previous definitions. 

We start proving that the first definition implies the
second one: *)

lemma le1_to_le2: ∀n,m:nat.le1 n m → le2 n m.
(* This is the proof pattern we shall follow: 
--------------------------------------------------- @npeqm
n:nat,m:nat,∃p:nat.n+p=m,
p:nat,npeqm:n+p=m  ⊢ n+p=m
----------------------------------------------- @(le_witness n m p)
n:nat,m:nat,∃p:nat.n+p=m,
p:nat,npeqm:n+p=m  ⊢ n+p=m→le2 n m
----------------------------------------------- #p #npeqm
n:nat,m:nat,∃p:nat.n+p=m 
                   ⊢ ∀x:ℕ.n+x=m→le2 n m
----------------------------------------------- elim le1
n:nat,m:nat,∃p:nat.n+p=m 
                   ⊢ le2 n m
----------------------------------- normalize in le1;
n:nat,m:nat,le1 n m ⊢ le2 n m
------------------------------- #n #m #le1
∀n,m:nat.le1 n m → le2 n m                    *)
#n #m #le1 
normalize in le1; elim le1 (* (0) *)
#p #npeqm @(le_witness n m p) @npeqm qed .

(* Then, the second definition implies the first one: *)
lemma le2_to_le1: ∀n,m:nat.le2 n m → le1 n m.
(* This is the proof pattern we shall follow: 
---------- (ex_intro nat (λp:ℕ.n+p=m)) ---------
n:ℕ,m:ℕ,le2:le2 n m ⊢ ∀p:ℕ.n+p=m → ∃p0:ℕ.n+p0=m
------------------------------------------------ normalize
n:ℕ,m:ℕ,le2:le2 n m ⊢ ∀p:ℕ.n+p=m → le1 n m
------------------------------------------- elim le2
n:ℕ,m:ℕ,le2:le2 n m ⊢ le1 n m
-------------------------------- #n #m #le2
∀n:ℕ.∀m:ℕ.le2 n m→le1 n m                      *)
#n #m #le2 elim le2 normalize (* (1) *)
(* (* One may *) check  (ex_intro nat (λp:ℕ.n+p=m)) *)
@(ex_intro nat (λp:ℕ.n+p=m)) (* (2) *) 
qed .

(* In the previous proof we do not follow  original Asperti's
proof pattern. We directly exploit ex_intro, defined in 
lib/basics/logic.ma whose type is:

     eq_intro: ∀A:Type.∀P:A→Prop.∀x:A.Px→∃x:A.Px

I have do guess the two arguments of ex_intro. In fact,
I have experimented with the original Asperti's proof pattern
which, keep going from (1) above, must develop as follows:

    #p #npeqm  @(ex_intro ? ? p npeqm))

Specifically,
    check (ex_intro ? ? p npeqm)) 
lets Matita to automatically build:
    (ex_intro ℕ (λ_:ℕ.n+__1=m) p npeqm:∃_:ℕ.n+__1=m)
from which one can synthesize (2).

We remark that the proof of le2_to_le1 is slightly more 
compact than the proof of le1_to_le2. The reason is that
le2_to_le1 does not require the normalization of the 
definition of le2 before eliminating it as in (0) above. 
This is one of the practical reason for preferring le2 over 
le1. More generally, the existential quantifier is just a 
particular case of inductive type, and the direct definition 
of a property as an inductive types usually allows a simpler
and more direct destructuration of the corresponding 
definition. *)

(**************** Section 2.1 Recursive properties ***)
(* The previous definition of le relies on the definition of 
the sum, that is not very elegant. An alternative way to look 
at the less or equal relation is as the smallest relation R 
being reflexive and such that R n m implies R n (S m). This 
notion is precisely captured by the following inductive type: *)
inductive le (n:nat) : nat → Prop ≝
| le_n : le n n
| le_S : ∀ m:nat. le n m → le n (S m).

(* Again, let us prove the equivalence between this definition 
and the definition of le2. As suggested by the original
tutorial, we start showing why the tactics we learned so far
are not enough. To experiment it, just uncomment in the
right way. *)
(* <-- Erase this....
lemma le2_to_le_not_general_enough: ∀ n,m:nat. le2 n m → le n m.
(*  As suggested, one can start as follows: *)
#n #m #le2 elim le2 #p 
(* We get to: 
   n:ℕ,m:ℕ,le2:le2 n m,p:ℕ ⊢ n+p=m→le n m
At this point, we can try to proceed by induction on p: *) 
elim p
[ (* We can prove the base case *)
  normalize <(plus_n_O n) #nm <nm @le_n 
| (* However the assumptions are too weak 
     and we get stuck.  *)
  #x #ind #H 
] .... and erase this --> *)
 
(* In fact, in the course of the proof of le_to_le2
instead of getting to the point where the goal is
           n+p=m→le n m
we need to arrive to the stronger goal:
           ∀m:ℕ.n+p=m→le n m
The tactic we need is 
     generalize in match m; 
The working proof follows.  *)

lemma le2_to_le: ∀ n,m:nat. le2 n m → le n m .
(* 
The following proof can be seen as split into two
phases. The first one aims at getting to the goal
   n:nat,p:ℕ ⊢ ∀m:nat.n+p=m → le n m (1)
which we shall prove by inducton on 

The goal (1) here above needs the introduction to
the right of ∀m, after m has been moved among the
assumptions to discharge all the other assumptions
as required:

n:nat,p:ℕ ⊢ ∀m:nat.n+p=m → le n m
------------------------------------ generalize in match m;
n:nat,m:nat,p:ℕ ⊢ n+p=m → le n m
------------------------------------ #p
n:nat,m:nat ⊢ ∀p:ℕ.n+p=m→le n m
------------------------------------ elim le2 -le2
n:nat,m:nat,le2 n m ⊢ le n m
------------------------------------ #n #m #le2 
∀n,m:nat.le2 n m → le n m         *)
#n #m #le2 elim le2 -le2
#p generalize in match m;
(* The second part proves (1) by induction on p: *)
elim p
[ <(plus_n_O n) #n' #neqn' <neqn' @le_n 
| #x #Hind #y #nSxeqy <nSxeqy <(plus_n_Sm) @(le_S)
  @(Hind (n+x)) 
  (* eq_f2 is in lib/basics/logic.ma *)
  @eq_f2 @refl @refl
] qed .

(* The converse holds as well: *)
lemma le_to_le2: ∀ n,m:nat. le n m → le2 n m .
#n #m #le elim le -le
[ @(le_witness n n O) <(plus_n_O n) @refl
| (* 
  *)
  #x #H -H 
  #le2 elim le2 -le2
  #p 
  (* The coming steps have n,m,x,p as global assumptions and essentially
     build the following proof:
     
      plus_monotone
    ----------------- -------------
    ⊢ n+p=x→S(n+p)=Sx n+p=x ⊢ n+p=x   plus_n_Sm      
 →E--------------------------------  -------------   
         n+p=x ⊢ S(n+p)=Sx          ⊢ S(n+p)=n+Sp   ∀n,m,p.n+p=m->le2 n (S x) 
      eq ----------------------------------------   -------------------------
                        n+p=x ⊢ n+Sp=Sx              ⊢ n+Sp=Sx → le2 n (S x) 
                     →E-----------------------------------------------------
                                  n+p=x ⊢ le2 n (S x)
                             →I-----------------------
                                 ⊢ n+p=x → le2 n (S x)                  *)
  #npeqx
  (* check (plus_monotone (n+p) x npeqx) *) 
  lapply (plus_monotone (n+p) x npeqx) -npeqx
  >(plus_n_Sm)
  (* check (le_witness n (S x) (S p)) *)
  @(le_witness n (S x) (S p))
  ] qed .

(**************** Section 2.2 Prop vs. Bool ***)
(* The definition of le of the previous section does not give an 
effective way to decide if n is less or equal to m. What we are looking 
for is a binary boolean function returning true if n ≤ m, and f alse 
otherwise. Such a computable function is usually called a decision 
procedure. A property admitting a decision procedure is called recursive,
or decidable. We start defining the type of booleans as the smallest type
containing the two elements true and false: *)
inductive bool : Type[0] ≝
| true : bool
| false : bool.

(* Then, we define a decision procedure for the less or equal relation: *)
let rec leb n m ≝ 
  match n with
  [ O ⇒ true | (S p) ⇒ match m with
                       [ O ⇒ false | (S q) ⇒ leb p q]].
                             
(* Once given a decision procedure, it is convenient to define a
corresponding elimination principle, which relates in a very general
way the boolean function to its propositional counterpart (le). In our 
case the boolean function is leb, and its propositional counterpart 
is le. The elimination principle says that:
for all natural numbers n and m, and any proposition P over booleans, 
provided we may prove (P true) under the assumption (le n m), and 
(P false) under the assumption ¬(le n m), then we can conclude 
(P (leb n m)). Namely:

  (n ≤ m → (P true)) → (n ≰ m → (P false)) → P (leb n m)

The proof requires preliminary steps: 
1) the proof of lemmas le_O_n, not_le_Sn_O, le_S_S, 
2) the definition of pred
3) the proof the pred is monotonic
4) the proof of le_S_S_to_le.
5) the proof of contraposition, called not_to_not in
lib/basics/logic.ma. Tuttavia, si potrebbe immaginare
di spostare contraposition nella sezione relativa alle
dimostrazioni per assurdo, visto il modo di dimostrarla. *)

lemma le_O_n : ∀n:nat. le O n.
#n (elim n) [@le_n | #x @le_S ] qed.

lemma not_le_Sn_O: ∀ n:nat. Not (le (S n) O).
#n @nmk #abs 
lapply ((le_to_le2 (S n) O) abs) -abs #le2 elim le2 -le2 #p
>(plus_sym (S n) p) <(plus_n_Sm p n) #abs destruct qed .
 
lemma le_S_S: ∀n,m:nat. (le n m) → (le (S n) (S m)).
#n #m #lenm elim lenm -lenm
[ @le_n | #x #H -H @(le_S) ] qed .

definition pred ≝
 λn. match n with [ O ⇒ O | S p ⇒ p].

theorem pred_monotonic: 
   ∀n,m:nat. le n m → le (pred n) (pred m).
#n #m #lenm (elim lenm)
[ @le_n 
| #x normalize in match (pred (S x)); 
  cases x normalize in match (pred O);
  [ #dummy #H @H 
  | #y normalize in match (pred (S y)); 
    #dummy @le_S ] qed.

lemma le_S_S_to_le: ∀n,m:nat. (le (S n) (S m)) → (le n m).
#n #m #leSnSn 
(* check ((pred_monotonic (S n) (S m)) leSnSn) *)
lapply ((pred_monotonic (S n) (S m)) leSnSn) 
normalize in match (pred (S n));
normalize in match (pred (S m)); #H @H qed .

theorem contraposition : ∀A,B:Prop. (A → B) → ¬B →¬A.
#A #B #AB #nB @nmk #A lapply nB lapply (AB A) @absurd qed .

theorem leb_elim: ∀n,m:nat. ∀P:bool → Prop.
(le n m → P true) → (Not (le n m) → P false) → P (leb n m).
@nat_elim2 
  [normalize #n #P #Pt #Pf @Pt @(le_O_n)
  |normalize #n #P #Pt #Pf @Pf @(not_le_Sn_O)
  |normalize #n #m #Hind #P #Pt #Pf @Hind
    [#lenm @Pt @le_S_S @lenm 
    |#nlenm @Pf lapply nlenm  @contraposition @le_S_S_to_le ]
qed.

(* Le seguenti prorietà che si trovano anche in 
lib/arithmetics/nat.ma ma sinora non mi paiono necessarie
per questo tutorial, quindi le commento. 


lemma le_n_Sn : ∀n:nat. le n (S n).
#n @le_S @le_n qed.

lemma le_tran : ∀n,m,o:nat. le n m → le m o → le n o.
#n #m #o #lenm #lemo (elim lemo) 
[@lenm | #x #dummy @le_S ]   qed. 

lemma  le_pred_n : ∀n:nat. le (pred n) n.
#n (elim n) 
[ normalize @le_n 
| #m #H normalize @(le_S) @le_n] qed . *)


(* Le seguenti proprietà sfruttano pesantemente leb_elim e sono
un esempio fondamentale.*)
theorem leb_true_to_le:∀n,m.leb n m = true → (le n m).
#n #m 
(* check (λb:bool. b=true→le n m)) *)
check (∀b:bool. b=true→le n m)
(* check ((λb:bool. b=true→le n m) (leb n m)) *)
@(leb_elim n m (λb:bool. b=true→le n m))

(* DA QUI !!!!!!!!!!!!!!!!!*)

@leb_elim // #_ #abs @False_ind /2/ qed.

theorem leb_false_to_not_le:∀n,m.
  leb n m = false → n ≰ m.
#n #m @leb_elim // #_ #abs @False_ind /2/ qed.

theorem le_to_leb_true: ∀n,m. n ≤ m → leb n m = true.
#n #m @leb_elim // #H #H1 @False_ind /2/ qed.

theorem not_le_to_leb_false: ∀n,m. n ≰ m → leb n m = false.
#n #m @leb_elim // #H #H1 @False_ind /2/ qed.

theorem lt_to_leb_false: ∀n,m. m < n → leb n m = false.
/3/ qed.


(*****************************************************************)
(**************** Chapter 3. A non trivial example ***************)
(*****************************************************************)
(* In a way similar to plus we may define the product of two natural 
numbers: *)


let rec times n m ≝ 
 match n with [ O ⇒ 0 | S p ⇒ m + (times p m) ].

interpretation "natural times" 'times x y = (times x y).

definition divides1: nat \to nat \to Prop \def
\lambda n,m.\exist p:nat.m = times n p.

(* However, as we have seen, it is preferable to define divides as
the smallest property induced by a 'witness' p and a proof that 
m = np, namely: *)

inductive divides (n,m:nat) : Prop \def
witness : \forall p:nat.m = times n p \to divides n m.


(* Let us now address the decidability of divides, i.e. the problem
to define an algorithmic boolean function that taken in input two 
integers n and m returns true if n divides m, and f alse otherwise.
A convenient way to proceed is to address the slightly more general
problem to compute the modulus (mod) of two numbers (i.e. the rest
of an integewr division); obviously n divides m if and only if 
m mod n = 0. The natural way to define mod as a recursive function 
would look something like the following: *)

let rec mod m n: nat \def
match (leb (S m) n) with
[ true \Rightarrow m
| false \Rightarrow mod (m-n) n
]

(* The problem with this definition is that the calculus is based on 
a particular kind or recursion that must be guaranteed to be 
well-founded (never diverge) . This is typically the case when the 
recursive parameter 'decreases' in the recursive call. Unfortunately,
there is no trivial way, for the system, to understand that m − n is 
'smaller' than m w.r.t. some well founded ordering
(minus is a user defined operation!). What the system is able to 
understand is essentially a syntactic ordering, based on the structure
of inductive data: for instance n is 'smaller' of S n.
A simple but effective approach to this problem is that of defining 
an auxiliary function accepting in input an extra-parameter t 
providing an upper bound to the complexity of the function, and then 
recurring on such an argument. For instance, in the case of the 
modulus, we may eventually complete the computation of mod m n in 
less than m steps. So, we define: *)

let rec mod_aux t m n: nat \def
match (leb (S m) n) with
[ true \Rightarrow m
| false \Rightarrow
match t with
[O \Rightarrow m
(* if t is large enough this case never happens *)
|(S t1) \Rightarrow mod_aux t1 (m-n) n
]
].

definition mod : nat \to nat \to nat \def
\lambda m,n.mod_aux m m n.

(* When we define a function having several cases as the previous 
one, it is good practice to specify the behavour with a distinct 
lemma for each possible branch. In the case of the previous function,
we have the following relevant cases, whose proof is more or less 
straightforward. The only novelty is the use of the change tactic, 
that allows to replace a goal with an equivalent one (up to 
convertibility). Sometimes, the heuristic used by the simplify 
tactic simplifies too much, and it turns out to be convenient to 
give the system the expected transformation in an explicit way. *)

lemma O_to_mod_aux: \forall m,n. mod_aux O m n = m.
intros.
simplify.elim (leb (S m) n);reflexivity.
qed.

lemma lt_to_mod_aux:
\forall t,m,n. m < n \to mod_aux (S t) m n = m.
intros.
change with
( match (leb (S m) n) with
[ true \Rightarrow m
| false \Rightarrow mod_aux t (m-n) n] = m).
rewrite > (le_to_leb_true ? ? H).
reflexivity.
qed.

lemma le_to_mod_aux:
\forall t,m,n.
n \le m \to mod_aux (S t) m n = mod_aux t (m-n) n.
intros.
change with
(match (leb (S m) n) with
[ true \Rightarrow m
| false \Rightarrow mod_aux t (m-n) n] = mod_aux t (m-n) n).
apply (leb_elim (S m) n);intro
[apply False_ind.apply (le_to_not_lt ? ? H).apply H1
|reflexivity
]
qed.

(* In order to understand the use of the previous lemmas, let us 
try to prove a simple property of the modulus operation, namely that
for any positive n, m mod n < n. The proof has the following 
structure: *)

theorem lt_mod_aux_m_m:
\forall n. O < n \to
\forall t,m. m \leq t \to (mod_aux t m n) < n.
intros 3.
elim t
[rewrite > O_to_mod_aux.
apply (le_n_O_elim ? H1).
assumption
|elim (decidable_lt m n)
[rewrite > lt_to_mod_aux[assumption|assumption]
|rewrite > le_to_mod_aux
[apply H1.
...
|apply not_lt_to_le.
assumption
]
]
]
qed.

(* Mimicking the definition of mod_aux, the proof proceeds by 
induction on the recursive parameter t. The case t = 0 is closed 
by O_to_mod_aux; in case t = Sn1, we distinguish two more cases 
according the situations m < n or m ≥ n. In the former case, we use 
lt_to_mod_aux while in the latter we use le_to_mod_aux
and the inductive hypothesis H1. The dots correspond to a trivial 
but formally cumbersome fragment of the proof. Indeed, after 
applying the inductive hypothesis H1 we are left with the following 
goal: *)


(* Very likely here it will benecessary to expand what 
Andrea writes .... *)

(* The proof requires several elementary arithmetical results, 
but is not particualry informative, so we shall skip it here.
Having defined the modulus, we define: *)

definition divides_b : nat \to nat \to bool \def
\lambda n,m :nat. (eqb (m \mod n) O).
